// 保存 Blob 为本地文件
export function saveBlob(blob: Blob, fileName: string) {
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.href = url
  a.download = fileName
  document.body.appendChild(a)
  a.click()
  a.remove()
  URL.revokeObjectURL(url)
}

export type GetMetaFn = (id: string) => Promise<{
  totalSize: number | null
  acceptRanges: boolean
  contentType?: string
  fileNameFromDisposition?: string
}>

export type DownloadRangeFn = (params: {
  id: string
  start: number
  endExclusive: number
  signal?: AbortSignal
  onProgress?: (evt: ProgressEvent) => void
}) => Promise<{ data: ArrayBuffer; contentType?: string }>

export type DownloadInChunksOptions = {
  id: string
  fileNameFallback?: string
  chunkSize?: number
  getMeta: GetMetaFn
  downloadRange: DownloadRangeFn
  onProgress?: (pct: number, downloaded: number, total: number | null) => void
  signal?: AbortSignal
}

// 简化版分片下载（无暂停/继续管理，由调用方控制 AbortController）
export async function downloadInChunks(opts: DownloadInChunksOptions): Promise<{ blob: Blob; fileName: string } | { blob: null; fileName: string }>
{
  const CHUNK = Math.max(256 * 1024, opts.chunkSize ?? 1024 * 1024)
  const meta = await opts.getMeta(opts.id)
  const total = meta.totalSize
  const acceptRanges = meta.acceptRanges
  const finalName = opts.fileNameFallback || meta.fileNameFromDisposition || `file-${opts.id}`

  if (!acceptRanges || !Number.isFinite(total)) {
    // 无断点续传信息，交由上层做整文件下载
    return { blob: null, fileName: finalName }
  }

  let offset = 0
  const buffers: ArrayBuffer[] = []
  while (offset < (total || 0)) {
    const endExclusive = Math.min(offset + CHUNK, total as number)
    const { data, contentType } = await opts.downloadRange({ id: opts.id, start: offset, endExclusive, signal: opts.signal })
    buffers.push(data)
    offset = endExclusive
    if (opts.onProgress) opts.onProgress(Math.round((offset / (total || 1)) * 100), offset, total)
    if (offset >= (total || 0)) {
      const blob = new Blob(buffers, { type: contentType || 'application/octet-stream' })
      return { blob, fileName: finalName }
    }
  }
  // 理论上不会到达此处
  const blob = new Blob(buffers, { type: 'application/octet-stream' })
  return { blob, fileName: finalName }
}
